﻿using System;
using System.IO;
using System.Text;
using System.Data;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Security.Cryptography;
using System.Runtime;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.SqlServer.Server;

namespace PickGold.SqlServer
{
	/// <summary>
	/// 位操作支持
	/// </summary>
	[Serializable]
	[SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToDuplicates = true, IsInvariantToNulls = false, IsInvariantToOrder = true, IsNullIfEmpty = true, MaxByteSize = SqlUserDefinedAggregateAttribute.MaxByteSizeValue)]
	public sealed class AllIntAnd : IAggregate<SqlInt64, AllIntAnd>, INullable, IBinarySerialize
	{
		/// <summary/>
		public SqlInt64 Value;

		/// <summary>
		/// 指示结构是否为 null。此属性为只读。
		/// </summary>
		public bool IsNull
		{
			get
			{
				return this.Value.IsNull;
			}
		}

		/// <summary>
		/// 查询处理器使用此方法初始化聚合的计算
		/// 对于查询处理器正在聚合的每个组调用此方法一次
		/// 查询处理器可以选择重用聚合类的同一实例来计算多个组的聚合
		/// 方法应在上一次使用此实例后根据需要执行清除，并允许重新启动新的聚合计算
		/// </summary>
		public void Init()
		{
			this.Value = SqlInt64.Null;
		}

		/// <summary>
		/// 查询处理器使用此方法累计聚合值
		/// 对于正在聚合的组中的每个值调用此方法一次
		/// 查询处理器仅在为聚合类的指定实例调用Init方法之后才调用此方法
		/// 此方法的实现应更新实例的状态以反映正在传递的参数值的累计
		/// </summary>
		/// <param name="value"></param>
		public void Accumulate(SqlInt64 value)
		{
			if (this.Value.IsNull || value.IsNull)
				this.Value = value.Value;
			else
				this.Value = this.Value & value.Value;
		}

		/// <summary>
		/// 可以将此聚合的另一实例与当前实例合并
		/// 查询处理器使用此方法合并聚合的多个部分计算
		/// </summary>
		/// <param name="value"></param>
		public void Merge(AllIntAnd value)
		{
			if (this.Value.IsNull || value.IsNull)
				this.Value = value.Value;
			else
				this.Value = this.Value & value.Value;
		}

		/// <summary>
		/// 此方法完成聚合计算并返回聚合的结果
		/// </summary>
		/// <returns></returns>
		public SqlInt64 Terminate()
		{
			return this.Value;
		}

		void IBinarySerialize.Read(BinaryReader r)
		{
			if (r == null)
				return;

			var bs = new byte[8];
			r.Read(bs, 0, 8);
			this.Value = BitConverter.ToInt64(bs, 0);
		}

		void IBinarySerialize.Write(BinaryWriter w)
		{
			if (w != null && !this.Value.IsNull)
				w.Write(BitConverter.GetBytes(this.Value.Value));
		}

		/// <summary/>
		public static implicit operator SqlInt64(AllIntAnd value)
		{
			return value.Value;
		}
	}

	/// <summary>
	/// 位操作支持
	/// </summary>
	[Serializable]
	[SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToDuplicates = true, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = true, MaxByteSize = SqlUserDefinedAggregateAttribute.MaxByteSizeValue)]
	public sealed class AllIntOr : IAggregate<SqlInt64, AllIntOr>, INullable, IBinarySerialize
	{
		/// <summary/>
		public SqlInt64 Value;

		/// <summary>
		/// 指示结构是否为 null。此属性为只读。
		/// </summary>
		public bool IsNull
		{
			get
			{
				return this.Value.IsNull;
			}
		}

		/// <summary>
		/// 查询处理器使用此方法初始化聚合的计算
		/// 对于查询处理器正在聚合的每个组调用此方法一次
		/// 查询处理器可以选择重用聚合类的同一实例来计算多个组的聚合
		/// 方法应在上一次使用此实例后根据需要执行清除，并允许重新启动新的聚合计算
		/// </summary>
		public void Init()
		{
			this.Value = SqlInt64.Null;
		}

		/// <summary>
		/// 查询处理器使用此方法累计聚合值
		/// 对于正在聚合的组中的每个值调用此方法一次
		/// 查询处理器仅在为聚合类的指定实例调用Init方法之后才调用此方法
		/// 此方法的实现应更新实例的状态以反映正在传递的参数值的累计
		/// </summary>
		/// <param name="value"></param>
		public void Accumulate(SqlInt64 value)
		{
			if (value.IsNull)
				return;

			if (this.Value.IsNull)
				this.Value = value.Value;
			else
				this.Value = this.Value | value.Value;
		}

		/// <summary>
		/// 可以将此聚合的另一实例与当前实例合并
		/// 查询处理器使用此方法合并聚合的多个部分计算
		/// </summary>
		/// <param name="value"></param>
		public void Merge(AllIntOr value)
		{
			if (value.IsNull)
				return;

			if (this.Value.IsNull)
				this.Value = value.Value;
			else
				this.Value = this.Value | value.Value;
		}

		/// <summary>
		/// 此方法完成聚合计算并返回聚合的结果
		/// </summary>
		/// <returns></returns>
		public SqlInt64 Terminate()
		{
			return this.Value;
		}

		void IBinarySerialize.Read(BinaryReader r)
		{
			if (r == null)
				return;

			var bs = new byte[8];
			r.Read(bs, 0, 8);
			this.Value = BitConverter.ToInt64(bs, 0);
		}

		void IBinarySerialize.Write(BinaryWriter w)
		{
			if (w != null && !this.Value.IsNull)
				w.Write(BitConverter.GetBytes(this.Value.Value));
		}

		/// <summary/>
		public static implicit operator SqlInt64(AllIntOr value)
		{
			return value.Value;
		}
	}
}
